Skip to content

Feat(wallet): build TransactionSignerPanel component (#222) - #301

Merged
godamongstmen897 merged 201 commits into
Goldii-locks:mainfrom
MAN7A-afk:feat/222-transaction-signer-panel
Aug 31, 2026
Merged

Feat(wallet): build TransactionSignerPanel component (#222)#301
godamongstmen897 merged 201 commits into
Goldii-locks:mainfrom
MAN7A-afk:feat/222-transaction-signer-panel

Conversation

@MAN7A-afk

@MAN7A-afk MAN7A-afk commented Aug 26, 2026

Copy link
Copy Markdown

Closes #222


Summary

Closes issue #222 (RTL tests for transaction_signer_component).

What changed

app/components/TransactionSignerPanel.tsx — new file

A wallet-agnostic sign-transaction panel. On mount it parses the supplied
XDR, shows a human-readable transaction preview, then lets the user confirm
or cancel before the wallet extension is invoked.

Props:

Prop Type Purpose
xdr string Base-64 XDR to sign
selectedWalletId SupportedWalletId Routes to the correct wallet impl
networkPassphrase string? Defaults to Testnet
signTransaction (xdr) => Promise<string> WalletContext sign fn or compatible
onSigned (signedXdr) => void Called on success
onRejected () => void? Called on Cancel
onError (error) => void? Called on signing failure
label string? Optional subtitle above the preview

States:
parse-error XDR unparseable on mount → error message + Dismiss idle Structure preview + Sign + Cancel signing Buttons disabled, spinner, wallet extension open success Green confirmation, onSigned fired error Red error message, Retry + Cancel, onError fired

Signing is 100% delegated to useWalletMultiSigAssembly — no new XDR
parsing or signing logic. Works for all four wallets (freighter, albedo,
xbull, hana) through the unified hook.


No regressions

Test Files 18 passed (18) Tests 266 passed (266)

Great-O and others added 12 commits August 26, 2026 11:38
- Add DEFAULT_SIGNING_TIMEOUT_MS = 60_000 configurable constant
- Add TxSignRequest interface, TxSignatureTimeoutError class,
  clearTxSensitiveMemory helper, and signTxWithTimeout function to
  app/lib/transactions.ts, matching the setTimeout + Promise.race
  pattern used by all other connector helpers in the codebase
- Wire signTxWithTimeout into submitContractTransaction via optional
  signingTimeoutMs param (defaults to the constant); on timeout the
  operation is aborted and any sensitive payload memory is zeroed
- Add __tests__/transactions_timeout.test.ts with 21 test cases
  covering: timeout fires, memory cleared, successful signing flow,
  pre-deadline no-early-fire, timer cleanup, error propagation,
  default constant, TxSignatureTimeoutError class, and
  clearTxSensitiveMemory helper
Adds app/components/TransactionSignerPanel.tsx — a wallet-agnostic
sign-transaction interface that unblocks issue Goldii-locks#222 (RTL tests).

- Parses supplied XDR on mount via useWalletMultiSigAssembly.parseStructure
  and displays a structure preview (source account, fee, operation count,
  existing signatures)
- States: idle -> signing -> success | error | parse-error
- Sign button delegates to hook.signTransaction(xdr, signTransaction) —
  no new XDR parsing or signing logic introduced
- Retry button returns to idle on signing failure
- Cancel/Dismiss calls onRejected() and resets state
- onSigned, onRejected, onError callbacks for parent integration
- Works for all four supported wallets (freighter, albedo, xbull, hana)
  through the unified useWalletMultiSigAssembly hook
- Replace hardcoded empty message with EmptyStateCard component
- Display briefcase icon for job-related context
- Show descriptive title and explanation text
- Include role badges (Client, Freelancer, Arbiter) showing available participation options
- Add comprehensive test coverage with 16 test cases
- Ensure proper accessibility with region landmarks and aria-labels
- Validates placeholder display under empty data states
…, desktop

- Add responsive padding and spacing (px-3 sm:px-6) for mobile-first approach
- Implement responsive typography scaling (text-xl sm:text-2xl md:text-3xl)
- Stack layout vertically on mobile, horizontal on tablet/desktop
- Apply responsive grid layouts (grid-cols-1 sm:grid-cols-2 lg:grid-cols-3)
- Make search form full-width on mobile, inline on tablet+
- Add responsive gaps and margins throughout
- Implement horizontal overflow handling for pagination on mobile
- Reduce button padding and font sizes on mobile viewports
- Add comprehensive responsive design test suite with 20 test cases
- Validate layout at mobile (< 640px), tablet (640-1024px), desktop (> 1024px)
…yling

- Add focus-visible ring-2 styling on all interactive elements (indigo-500)
- Implement hover state transitions with smooth animations (transition-all duration-200)
- Add active state styling for button press feedback
- Style disabled buttons with opacity-50 and cursor-not-allowed
- Prevent hover effects on disabled buttons (disabled:hover:bg-gray-900)
- Apply ring-offset for focus states on dark background (ring-offset-gray-950)
- Use inset focus ring on job expand buttons for better UX
- Add focus-visible:outline-none to remove browser defaults
- Implement smooth transitions on all state changes
- Add comprehensive test suite with 25 test cases validating:
  - Search input focus and hover states
  - Search button focus, hover, and active states
  - Role filter button states and transitions
  - Job expand button interactive states
  - Pagination button states and disabled styling
  - Accessibility compliance and transitions
…onSignerPanel

- Move state declarations before closeModal callback (WalletSelectorModal)
- Remove eslint-disable and add missing hook dependency (TransactionSignerPanel)
@drips-wave

drips-wave Bot commented Aug 27, 2026

Copy link
Copy Markdown

@MAN7A-afk Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

MAN7A-afk and others added 17 commits August 27, 2026 19:25
Implements the app dark/light theme toggle as a keyboard-operable,
ARIA-compliant switch (role=switch, aria-checked, aria-label) that
persists the chosen theme to localStorage and applies it to the document
root. Adds React Testing Library tests verifying node rendering,
accessible state, theme application, keyboard operation and persistence.

Closes Goldii-locks#319
Implements the navbar alert bell badge as a keyboard-operable
(role=button) disclosure with ARIA compliance (Goldii-locks#320): accessible name,
aria-haspopup/aria-expanded/aria-controls, aria-live announcement
regions, aria-hidden on decorative glyphs, focus-visible rings and
design-token contrast.

Adds field error indicators and alerts (Goldii-locks#324): validation field configs
render role=alert error text that toggles as validation triggers, wired
via aria-describedby and counted toward the unread badge.

Adds React Testing Library tests covering both requirements.

Closes Goldii-locks#320
Closes Goldii-locks#324
Stack the stat grid and content rows to a single column on mobile,
two on tablet, three on desktop, and use responsive padding/spacing
so LoadingSkeleton scales cleanly at every breakpoint.

Closes Goldii-locks#275
Fade the skeleton in on mount (animate-fade-in) instead of popping in
abruptly, and stagger each placeholder bar's pulse animation-delay so
the loading state reads as a smooth wave rather than a flat blink.

Closes Goldii-locks#278
Replace the bare "No jobs found" line with a reusable EmptyState
component (icon, heading, supporting copy) shown once loading
finishes with zero jobs for the connected wallet.

Closes Goldii-locks#276
godamongstmen897 and others added 28 commits August 31, 2026 16:17
…k-switcher-responsive

fix(Goldii-locks#312): Add responsive sizing layouts on dark_mode_switcher
…ing-skeleton-stories

feat: add Storybook stories for LoadingSkeleton (closes Goldii-locks#281)
…e_raise_modal

Implement overlay wrappers on dispute_raise_modal to fit constraints on mobile device screen heights.

Changes:
- Added overlayWrapper class with flex layout and max-h-[92vh] for mobile height constraints
- Added scrollableContent class to allow middle content to scroll independently
- Updated panel structure to use overlay wrapper with header, scrollable content, and actions
- Added flex-shrink-0 to header and actions to prevent shrinking
- Added comprehensive test cases for mobile viewport validation
No textual conflict against current main -- GitHub's cached mergeability
had gone stale (it reported DIRTY where a local three-way merge is
clean), the same as on Goldii-locks#366. Merging main in here refreshes the head so
CI runs against it.

lint 0 errors / tsc 0 errors / 2035 tests passing / build OK
…e-modal-stories

Feat: Implemented Storybook Interface for Dispute Raise ModaL
…he shared badge

This branch predates the LoadingSkeleton rewrite (Goldii-locks#349/Goldii-locks#351/Goldii-locks#352/Goldii-locks#354)
and the WalletBadge consolidation, and git merged it without conflicts
into something that does not parse -- the classic silent damage:

- LoadingSkeleton.tsx ended up as this branch's pre-token markup
  concatenated with main's current component, leaving an unterminated
  JSX block followed by `interface LoadingSkeletonProps`.
- WalletBadge.tsx ended up with two complete implementations: two
  `formatAddress` declarations and two `export default`s.
- Navbar.tsx and wallet_badge.test.tsx each got duplicate import lines.

LoadingSkeleton and SignatureTimeoutAlert are incidental to this PR --
its subject is the wallet badge -- and the branch's own copies were
already broken before the merge (its SignatureTimeoutAlert interleaves a
useEffect into the existing useMemo, leaving two catch blocks and an
undefined setParseMessage). Both were taken from main.

The badge work itself is real and entirely additive: 16 of its 33 cases
already passed against main's component, and the other 17 cover features
main did not have. Those were added to main's derived-status rendering
rather than replacing it:

  isValidStellarAddress   exported; G + 55 base32 chars, format only
  error / fieldError      wallet-field-error + wallet-error-text,
                          aria-invalid, red status dot
  validateAddress         flags a malformed address the same way
  alert                   wallet-alert-badge, amber dot; error wins
  empty placeholders      wallet-badge-placeholder, -custom and
                          wallet-empty-list-placeholder for empty
                          accounts/wallets/items, plus data-empty-state

One distinction worth noting: a present-but-blank address (`""`) is an
empty state, while a missing one (`null`) stays the ordinary
disconnected badge unless the caller passes placeholder copy. The
branch's own tests require both readings.

All four wallet-badge suites now pass together.

lint 0 errors / tsc 0 errors / 2052 tests passing / build OK
The branch's lockfile is not valid JSON -- it fails to parse at offset
101100 in the branch itself, before any merge -- which is why CI died at
"Install dependencies" with npm error code EUSAGE rather than at a
lint or test step.

The branch does not modify package.json at all, so its 5002-line
lockfile change had nothing to express; main's lockfile is the correct
one for these dependencies. Verified with a clean npm ci against the
merged package.json.

lint 0 errors / tsc 0 errors / 2052 tests passing / build OK
…ole-errors-and-transaction-tracking-in-network-sync-checker

# Conflicts:
#	__tests__/freighter_connector.component.test.tsx
#	__tests__/freighter_multisig_hook.test.ts
#	__tests__/signature_timeout_alert.test.tsx
#	__tests__/signature_timeout_alert_timeout.test.ts
#	app/components/SignatureTimeoutAlert.tsx
#	vitest.setup.ts
…pty-placeholder

feat(wallet): render descriptive placeholders for empty data states in wallet_badge
…lready carries

This branch and its three siblings (Goldii-locks#359/Goldii-locks#360/Goldii-locks#361) share a base of
commits that rework the same four test files and SignatureTimeoutAlert,
so most of the conflict here is the same work expressed twice:

- signature_timeout_alert_timeout.test.ts: `onRejected` vs main's
  `settled` for the same catch-before-advance handle.
- freighter_multisig_hook.test.ts: an equivalent signed-envelope builder
  to main's `buildSignedEnvelopeXdr`.
- signature_timeout_alert.test.tsx: the same act() calls, reformatted.
- freighter_connector.component.test.tsx: a different mocking strategy
  for the same cases.

None of those four adds a test case -- the it() counts are identical to
this branch's own merge base -- so main's versions were kept and this
branch's rewrites dropped. SignatureTimeoutAlert took the branch's
explanatory comment, which describes what main already does.

vitest.setup.ts combines both: the branch's guard is the better one (it
also catches the experimental Node localStorage global that reads as
undefined and shadows jsdom's), while main's defined the property on
both globalThis and window. The merged version does both.

The branch's actual deliverable is untouched: NetworkSyncChecker.tsx and
its 300-line component suite.

lint 0 errors / tsc 0 errors / 2061 tests passing / build OK
…ct-testing-library-assertions-for-network-sync-checker

[162] Write React Testing Library assertions for network_sync_checker
…eractive-states-for-notification-bell

# Conflicts:
#	__tests__/freighter_connector.component.test.tsx
#	__tests__/freighter_multisig_hook.test.ts
#	__tests__/signature_timeout_alert.test.tsx
#	__tests__/signature_timeout_alert_timeout.test.ts
#	app/components/SignatureTimeoutAlert.tsx
#	app/components/notification_bell.tsx
#	vitest.setup.ts
Only vitest.setup.ts conflicted, and main already carries the combined
version resolved on Goldii-locks#358 -- which includes this branch's own guard for
the experimental Node localStorage global. Took main's.

The branch's deliverable lands unchanged: the network_sync_checker
logging rework and its 197-line suite.

lint 0 errors / tsc 0 errors / 2072 tests passing / build OK
…y-list-views-for-notification-bell

# Conflicts:
#	__tests__/freighter_connector.component.test.tsx
#	__tests__/freighter_multisig_hook.test.ts
#	__tests__/signature_timeout_alert.test.tsx
#	__tests__/signature_timeout_alert_timeout.test.ts
#	app/components/notification_bell.tsx
#	vitest.setup.ts
…nsole-errors-and-transaction-tracking-in-network-sync-checker

[161] Format console errors and transaction tracking in network_sync_checker
…nteractive-states-for-notification-bell

[321] Add premium interactive states to notification_bell
…pty-list-views-for-notification-bell

[323] Design empty list display views for notification_bell
…e modal

The branch predates Goldii-locks#375's rewrite of DisputeRaiseModal, and its own
edit to that file is broken independently of the merge: it deletes the
counterparty <dd>'s closing tags and splices a stray label/textarea
fragment in their place, so the branch does not parse. The merge
inherited that.

The lib half is sound and is the real contribution, so it was kept and
the component rebuilt around it: the panel becomes a plain flex column,
DISPUTE_MODAL_CLASSES.overlayWrapper takes the padding and the height
cap, and a scrollableContent region wraps everything between the header
and the actions -- so on a short viewport the middle scrolls while the
title and buttons stay pinned.

Two assertions in the responsive suite described the old arrangement and
now follow it: the p-4/sm:p-6/lg:p-8 checks moved from the panel to the
wrapper, and the panel's overflow-y-auto check became a query for the
scrollable region inside it.

The branch's own "keeps action buttons clickable" case also assumed the
confirm button is live with an empty reason, which Goldii-locks#375 changed -- it now
fills the field first, which is what a user reaching those buttons would
have done anyway.

lint 0 errors / tsc 0 errors / 2098 tests passing / build OK
…spute-modal-mobile-overlay-wrappers

Goldii-locks#336 Handle mobile viewports navigation styling in dispute_raise_modal
Two Navbar conflicts: this branch swaps the inline provider select and
Connect button for a <WalletSelectorModal>. That is incidental to the
PR -- its subject is TransactionSignerPanel (Goldii-locks#222) and none of its tests
touch the Navbar -- and main's navbar-wallet-kit suite queries the
select by label and the button by name, so main's Navbar was kept.

TransactionSignerPanel then failed lint: it parsed the XDR in a mount
effect and wrote the result to three pieces of state, which
react-hooks/set-state-in-effect flags as cascading renders.

Parsing is a pure function of the XDR and the wallet/network in play, so
it now derives during render through useMemo. The signing lifecycle is
still real state (idle -> signing -> success/error), so it stays in
useState as `signingState`, with a parse failure outranking it:

  const state = parseErrorMessage ? "parse-error" : signingState;

Rendering is unchanged -- `state`, `structure` and `parseErrorMessage`
mean exactly what they did before.

lint 0 errors / tsc 0 errors / 2140 tests passing / build OK
@godamongstmen897
godamongstmen897 merged commit 42fa67c into Goldii-locks:main Aug 31, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write React Testing Library assertions for transaction_signer_component